#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "../../board.h"
#include "lv_pm.h"
#include "lvgl/src/lv_misc/lv_ll.h"
#include "backlight.h"

static lv_ll_t lv_pm_ll;
static int pm_state_cur = PM_ON;
static int pm_state_last = PM_ON;

int lv_pm_register(lv_pm_info_t *info)
{
    lv_pm_info_t *t;

    t = _lv_ll_ins_tail(&lv_pm_ll);
    if (!t) {
        printf("%s failed: no mem\n", __FUNCTION__);
        return -1;
    }

    memcpy(t, info, sizeof(lv_pm_info_t));
    return 0;
}

static uint32_t do_suspend(void)
{
    if(pm_state_last != PM_SUSPEND) {
        lv_pm_info_t *info, *info_next;

        info = _lv_ll_get_head(&lv_pm_ll);
        while (info) {
            if (info->suspend
                 && (info->part != LV_PM_PART_DISPLAY)
                 && (info->part != LV_PM_PART_TOUCH)) {
                info->suspend(info->data);
            }
            info_next = _lv_ll_get_next(&lv_pm_ll, info);
            info = info_next;
        }
        pm_state_last = PM_SUSPEND;
    }

    return sys_pm_set_state(pm_state_cur);
}

static void do_resume(void)
{
    if(pm_state_last == PM_ON)
        return;

    sys_pm_set_state(pm_state_cur);

    lv_pm_info_t *info, *info_next;

    info = _lv_ll_get_tail(&lv_pm_ll);
    while (info) {
        if (info->resume
            && (info->part != LV_PM_PART_DISPLAY)
            && (info->part != LV_PM_PART_TOUCH)) {
            info->resume(info->data);
        }
        info_next = _lv_ll_get_prev(&lv_pm_ll, info);
        info = info_next;
    }

    pm_state_last = PM_ON;
}

/* wake up event calls it */
uint32_t lv_pm_set_state(int state)
{
    pm_state_cur = state;
    if (state == PM_ON) {
        do_resume();
        return 0;
    } else {
        return do_suspend();
    }
}

uint32_t lv_pm_part_suspend(int part)
{
    lv_pm_info_t *info, *info_next;

    if (part == LV_PM_PART_DISPLAY) {
        lcd_backlight_off();
    }

    info = _lv_ll_get_head(&lv_pm_ll);
    while (info) {
        if (info->suspend && (info->part == part)) {
            info->suspend(info->data);
        }
        info_next = _lv_ll_get_next(&lv_pm_ll, info);
        info = info_next;
    }

    return 0;
}

uint32_t lv_pm_part_resume(int part)
{
    lv_pm_info_t *info, *info_next;

    info = _lv_ll_get_tail(&lv_pm_ll);
    while (info) {
        if (info->resume && (info->part == part)) {
            info->resume(info->data);
        }
        info_next = _lv_ll_get_prev(&lv_pm_ll, info);
        info = info_next;
    }

    if (part == LV_PM_PART_DISPLAY) {
        uos_sleep(20);
        lcd_backlight_on();
    }

    return 0;
}

int lv_pm_get_state(void)
{
     return pm_state_cur;
}

void lv_pm_init(void)
{
    _lv_ll_init(&lv_pm_ll, sizeof(lv_pm_info_t));
    sys_pm_init();
}

